//
// Created by Gao Shihao on 2023/8/11.
//

#ifndef PLC2LLVM_TYPEMACHINE_H
#define PLC2LLVM_TYPEMACHINE_H

#include <plc2llvm/TypeSystem/Type.h>
#include <plc2llvm/TypeSystem/BasicType.h>
#include <unordered_map>
#include <plc2llvm/ScopeSystem/ScopeManager.h>
#include <memory>
#include <plc2llvm/utils/Utils.h>

namespace plcst {

    // 定义一个typeMachine类
    // 单例类
    class TypeMachine {
    public:
        friend ScopeManager;

        static TypeMachine& getTypeMachine() {
            static TypeMachine machine;
            return machine;
        }

        // TypeMachine(TypeMachine const& ) = delete;
        // TypeMachine& operator=(TypeMachine const& ) = delete;

        bool isNumber(TypeKind t);

        bool isReal(TypeKind t);

        bool isInt(TypeKind t);

        bool isSignedInt(TypeKind t);

        bool isUnsignedInt(TypeKind t);

        bool isDateTime(TypeKind t);

        bool isDateType(TypeKind t);

        bool isDayType(TypeKind t);

        bool isDuringType(TypeKind t);

        bool isString(TypeKind t);

        bool isWString(TypeKind t);

        bool isBitstr(TypeKind t);


    private:

        static std::vector<std::shared_ptr<Type>> creatAllBasicType();

        // real typekind set
        std::set<TypeKind> realTypeKinds = {
            TypeKind::REAL,
            TypeKind::LREAL
        };

        // int typekind set
        std::set<TypeKind> intTypeKinds = {
            TypeKind::SINT,
            TypeKind::INT, 
            TypeKind::DINT, 
            TypeKind::LINT, // unsigned
            TypeKind::USINT,
            TypeKind::UINT,
            TypeKind::UDINT,
            TypeKind::ULINT // signed
        };

        // signed int set
        std::set<TypeKind> signedIntTypeKind = {
            TypeKind::SINT,
            TypeKind::INT, 
            TypeKind::DINT, 
            TypeKind::LINT // signed
        };

        // unsigned int typekind set
        std::set<TypeKind> unsignedIntTypeKind = {
            TypeKind::USINT,
            TypeKind::UINT,
            TypeKind::UDINT,
            TypeKind::ULINT // unsigned
        };

        // bitstr typekind set
        std::set<TypeKind> bitstrTypeKinds = {
            TypeKind::BOOL,
            TypeKind::BYTE,
            TypeKind::WORD,
            TypeKind::DWORD,
            TypeKind::LWORD
        };


        TypeMachine() = default;

    public:
        ~TypeMachine() = default;
    };
}

#endif //PLC2LLVM_TYPEMACHINE_H
